package com.htdata.iiot.api.pojo;

import com.htiiot.common.util.NumberTools;

import java.io.Serializable;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Base64;

/**
 * Device Number used by data stream, It is composed by user id(4bytes), thing id(4bytes), and component id(8bytes)
 * @author shanyou
 *
 */
public class DeviceNumber implements Serializable {
	/**
	 * 
	 */
	private static final long serialVersionUID = 3683836204742115180L;
	
	public static final int DEVICE_NUMBER_SIZE = 16; //16 bytes
	public static final int USER_ID_SIZE = 4;
	public static final int THING_ID_SIZE = 4;
	public static final int COMPONENT_ID_SIZE = 8;
	final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();
	
	private byte[] dnBytes = new byte[DEVICE_NUMBER_SIZE];

	public byte[] getDnBytes() {
		return dnBytes;
	}
	
	public DeviceNumber(byte[] uId, byte[] deviceId, byte[] metricId) {
		if (uId.length != USER_ID_SIZE || 
				deviceId.length != THING_ID_SIZE ||
				metricId.length != COMPONENT_ID_SIZE) {
			throw new IllegalArgumentException("input id length invalid");
		}
		
		System.arraycopy(uId, 0, dnBytes, 0, USER_ID_SIZE);
		System.arraycopy(deviceId, 0, dnBytes, 0 + USER_ID_SIZE, THING_ID_SIZE);
		System.arraycopy(metricId, 0, dnBytes, 0 + USER_ID_SIZE + THING_ID_SIZE, COMPONENT_ID_SIZE);
	}
	
	
	/**
	 * Init device number with integer and long type
	 * @param tenantid
	 * @param deviceid
	 * @param metricid
	 */
	public DeviceNumber(int tenantid, int deviceid, long metricid) {
		this(ByteBuffer.allocate(4).putInt(tenantid).array(),
				ByteBuffer.allocate(4).putInt(deviceid).array(),
				ByteBuffer.allocate(8).putLong(metricid).array());
	}
	
	public DeviceNumber(byte[] dnBytes) {
		if (dnBytes.length != DEVICE_NUMBER_SIZE) {
			throw new IllegalArgumentException("input bytes length invalid");
		}
		
		System.arraycopy(dnBytes, 0, this.dnBytes, 0, DEVICE_NUMBER_SIZE);
	}
	
	public String toBase64String() {
		 return new String(Base64.getEncoder().encode(dnBytes));
	}
	
	public String toHexString() {
		char[] hexChars = new char[dnBytes.length * 2];
	    for ( int j = 0; j < dnBytes.length; j++ ) {
	        int v = dnBytes[j] & 0xFF;
	        hexChars[j * 2] = hexArray[v >>> 4];
	        hexChars[j * 2 + 1] = hexArray[v & 0x0F];
	    }
	    return new String(hexChars);
	}
	
	public byte[] getTenantId() {
		return Arrays.copyOfRange(dnBytes, 0, USER_ID_SIZE);
	}

	public int getTenantIdInt() {
		return NumberTools.bytesToInt(getTenantId());
	}
	
	public byte[] getDeviceId() {
		return Arrays.copyOfRange(dnBytes, 0 + USER_ID_SIZE, USER_ID_SIZE + THING_ID_SIZE);
	}
	
	public int getDeviceIdInt() {
		return NumberTools.bytesToInt(getDeviceId());
	}

	public byte[] getMetricId() {
		return Arrays.copyOfRange(dnBytes, 0 + USER_ID_SIZE + THING_ID_SIZE, USER_ID_SIZE + THING_ID_SIZE + COMPONENT_ID_SIZE);
	}

	public long getMetricIdLong() {
		return NumberTools.bytesToLong(getMetricId());
	}
	
	public static final DeviceNumber fromBase64String(String base64Str) {
		byte[] base64Bytes = base64Str.getBytes();
		return new DeviceNumber(Base64.getDecoder().decode(base64Bytes));
	}
	
	public static final DeviceNumber fromHexString(String hexStr) {
		int len = hexStr.length();
	    byte[] data = new byte[len / 2];
	    for (int i = 0; i < len; i += 2) {
	        data[i / 2] = (byte) ((Character.digit(hexStr.charAt(i), 16) << 4)
	                             + Character.digit(hexStr.charAt(i+1), 16));
	    }
	    return new DeviceNumber(data);
	}

	public DeviceNumber(){

	}
}
